
package cn.zlg.common.datadump.executor;

import cn.afterturn.easypoi.excel.annotation.Excel;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import cn.zlg.common.datadump.annotation.DataDumpEntity;
import cn.zlg.common.datadump.bean.ImportFieldResult;
import cn.zlg.common.datadump.bean.ImportResult;
import cn.zlg.common.datadump.bean.ImportRowResult;
import cn.zlg.common.datadump.condition.HttpServletRequestQueryConditionBuilder;
import cn.zlg.common.datadump.convertor.FieldValueConvert;
import cn.zlg.common.datadump.enums.ImportDuplicateProcess;
import cn.zlg.common.datadump.enums.MultiRefEntityChooseStrategy;
import cn.zlg.common.datadump.processor.ImportEntityProcessor;
import cn.zlg.common.datadump.service.DataDumpDefRegistry;
import cn.zlg.common.datadump.util.QueryDslUtils;
import cn.zlg.common.springmvc.validate.bean.CustomNotNull;
import cn.zlg.common.springmvc.validate.bean.CustomValueCheck;
import cn.zlg.common.springmvc.validate.constraints.CustomValidator;
import cn.zlg.common.util.CollectionUtils;
import com.alibaba.fastjson.JSONObject;
import com.joysuch.wwyt.api.basedata.service.BpDepartSyncService;
import com.joysuch.wwyt.api.basedata.service.BpJobSyncService;
import com.joysuch.wwyt.api.dataaccess.OrientationDataSyncService;
import com.joysuch.wwyt.bp.entity.BpDepart;
import com.joysuch.wwyt.bp.entity.BpJob;
import com.joysuch.wwyt.bp.entity.contractor.BpContractor;
import com.joysuch.wwyt.bp.entity.contractor.BpContractorStaff;
import com.joysuch.wwyt.bp.enums.DataStateTypes;
import com.joysuch.wwyt.bp.repository.BpDepartDao;
import com.joysuch.wwyt.bp.repository.BpJobDao;
import com.joysuch.wwyt.bp.service.BpContractorService;
import com.joysuch.wwyt.bp.service.BpContractorStaffService;
import com.joysuch.wwyt.core.service.BaseConfigService;
import com.joysuch.wwyt.core.support.Context;
import com.joysuch.wwyt.datadump.biz.model.MajorHazardImportProcessAfterValidateMsgBean;
import com.joysuch.wwyt.datadump.biz.model.MhMajorHazardDumpBean;
import com.joysuch.wwyt.mh.service.MonitorPointDataWebSocketService;
import com.joysuch.wwyt.risk.entity.RiskDistrict;
import com.joysuch.wwyt.risk.entity.RiskEvaluationBusiness;
import com.joysuch.wwyt.risk.entity.RiskPoint;
import com.joysuch.wwyt.risk.enums.RiskPointStatus;
import com.joysuch.wwyt.risk.repository.RiskDistrictDao;
import com.joysuch.wwyt.risk.repository.RiskEvaluationBusinessDao;
import com.joysuch.wwyt.risk.repository.RiskPointEvaluationBusinessDao;
import com.joysuch.wwyt.risk.service.RiskEvaluationBusinessService;
import com.joysuch.wwyt.risk.service.RiskEvaluationControlService;
import com.joysuch.wwyt.util.ReflectUtil;
import com.joysuch.wwyt.util.SnowFlakeUtil;
import com.mysema.commons.lang.Assert;
import com.querydsl.core.Tuple;
import com.querydsl.core.types.Predicate;
import com.querydsl.core.types.dsl.EntityPathBase;
import com.querydsl.core.types.dsl.SimpleExpression;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.compress.utils.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import javax.validation.*;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.text.ParseException;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * jpa导入
 */
@Service
public class JPAQueryImportExecutor<F, T> implements ApplicationContextAware {

    private static final Logger logger = LoggerFactory.getLogger(JPAQueryImportExecutor.class);

    private static ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();

    @Autowired
    private JPAQueryFactory factory;

    @Autowired
    private EntityManager em;

    @Autowired
    private DataDumpDefRegistry dataDumpDefRegistry;

    @Autowired
    private BpContractorService bpContractorService;

    @Autowired
    private BpContractorStaffService bpContractorStaffService;

    @Autowired
    private BpJobSyncService bpJobSyncService;

    @Autowired
    private BpJobDao bpJobDao;

    @Autowired
    private BpDepartSyncService bpDepartSyncService;

    @Autowired
    private BpDepartDao bpDepartDao;

    @Autowired
    private BaseConfigService baseConfigService;

    @Autowired
    private RiskDistrictDao riskDistrictDao;

    @Autowired
    private RiskEvaluationControlService controlService;

    @Autowired
    private MonitorPointDataWebSocketService monitorPointDataWebSocketService;

    @Autowired
    private RiskPointEvaluationBusinessDao riskPointEvaluationBusinessDao;

    @Autowired
    private RiskEvaluationBusinessDao riskEvaluationBusinessDao;

    @Autowired
    private RiskEvaluationBusinessService riskEvaluationBusinessService;

    @Autowired
    private OrientationDataSyncService orientationDataSyncService;

    private ApplicationContext applicationContext;

    @Transactional
    public ImportResult doImport(Class<F> entity, List<F> originData, int startRowIndex, ImportDuplicateProcess duplicateProcess) throws Exception {
        if (originData == null || originData.isEmpty()) {
            return new ImportResult();
        }
        DataDumpEntity entityAnnotation = (DataDumpEntity) entity.getAnnotation(DataDumpEntity.class);
        List<ImportEntityProcessor> importEntityProcessors = findImportEntityProcessors(entityAnnotation);
        List<JPAQueryExportExecutor.FieldDescriptor> fieldDescriptors = JPAQueryExportExecutor.findFieldDescriptors(entity, entityAnnotation);
        fieldDescriptors.forEach(fd -> fd.field.setAccessible(true));
        extractEntityPropertyDescriptor(fieldDescriptors);
        List<JPAQueryExportExecutor.FieldDescriptor> keyFields = fieldDescriptors.stream().filter(fd -> fd.annotation.importKey()).collect(Collectors.toList());
        Assert.isTrue(keyFields.size() > 0, "导入对象" + entity.getName() + "没有唯一属性 ");
        Assert.notNull(entityAnnotation,
                String.format("类%s没有%s注解,无法解析 ", entity.getName(), DataDumpEntity.class.getSimpleName()));
        List<RowWrapper> rows = new ArrayList<>(originData.size());
        for (int i = 0; i < originData.size(); i++) {
            RowWrapper<F, T> rw = new RowWrapper<>();
            rw.origin = originData.get(i);
            rw.index = i + startRowIndex;
            rw.status = INIT;
            rw.stop = false;
            rows.add(rw);
        }
        processBeforeValidate(importEntityProcessors, rows, entityAnnotation);
        // 静态校验，校验必填、正则、长度、非空等
        staticValidate(entity, rows);
        // 自定义校验
        customValidator(entity, rows);
        // 验证Key选项是否为空
        validateKeyFields(keyFields, rows);
        processAfterValidate(entityAnnotation, importEntityProcessors, rows);
        // 数据格式转换
        createAndConvert(entity, entityAnnotation, fieldDescriptors, rows);
        processBeforeSave(entityAnnotation, importEntityProcessors, rows);
        // 保存
        doSave(entityAnnotation, fieldDescriptors, keyFields, rows, duplicateProcess, importEntityProcessors);
        processAfterSave(entityAnnotation, importEntityProcessors, rows);
        return createResult(rows);
    }

    private void processAfterValidate(DataDumpEntity entityAnnotation, List<ImportEntityProcessor> importEntityProcessors, List<RowWrapper> rows) {
        if (importEntityProcessors.size() > 0) {
            for (RowWrapper rw : rows) {
                if (rw.stop) {
                    continue;
                }
                try {
                    for (ImportEntityProcessor p : importEntityProcessors) {
                        rw.transformed = p.processAftertValidate(rw.origin, entityAnnotation);
                    }
                } catch (Exception e) {
                    String msg = e.getMessage();
                    boolean isJson = true;
                    // 危险源导入异常特殊处理
                    MajorHazardImportProcessAfterValidateMsgBean msgBean = null;
                    try {
                        msgBean = JSONObject.parseObject(msg, MajorHazardImportProcessAfterValidateMsgBean.class);
                    } catch (Exception e1) {
                        isJson = false;
                    }
                    rw.stop = true;
                    rw.status = DYNAMIC_VALIDATE_FAIL;
                    if (isJson) {
                        if (msgBean != null) {
                            addStaticFieldError(msgBean.getFileName(), msgBean.getFileName(), msgBean.getMsg(), rw);
                        }
                    } else {
                        addRowErrorMessage(rw, e.getMessage());
                    }

                }
            }
        }
    }

    private void extractEntityPropertyDescriptor(List<JPAQueryExportExecutor.FieldDescriptor> fieldDescriptors) {
        for (JPAQueryExportExecutor.FieldDescriptor fd : fieldDescriptors) {
            String fieldName = fd.entityPath.getMetadata().getName();
            PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(fd.entity.getType(), fieldName);
            if (pd != null && pd.getWriteMethod() != null) {
                fd.entityFieldPd = pd;
            } else {
                logger.warn("{}字段{}没有写入方法", fd.entity.getType().getName(), fieldName);
            }
        }
    }

    private void processBeforeValidate(List<ImportEntityProcessor> importEntityProcessors, List<RowWrapper> rows, DataDumpEntity anno) {
        if (importEntityProcessors.size() > 0) {
            for (RowWrapper rw : rows) {
                for (ImportEntityProcessor p : importEntityProcessors) {
                    rw.origin = p.processBeforeValidate(rw.origin, anno);
                }
            }
        }
    }

    private List<ImportEntityProcessor> findImportEntityProcessors(DataDumpEntity entityAnnotation) {
        List<ImportEntityProcessor> list = new ArrayList<>(entityAnnotation.importProcessors().length);
        for (Class<? extends ImportEntityProcessor> c : entityAnnotation.importProcessors()) {
            list.add(applicationContext.getBean(c));
        }
        return list;
    }

    private void validateKeyFields(List<JPAQueryExportExecutor.FieldDescriptor> keyFields, List<RowWrapper> rows) {
        for (RowWrapper rw : rows) {
            for (JPAQueryExportExecutor.FieldDescriptor fd : keyFields) {
                try {
                    Object v = fd.field.get(rw.origin);
                    if (v == null) {
                        rw.stop = true;
                        rw.status = STATIC_VALIDATE_FAIL;
                        addStaticFieldError(getFieldBizName(fd.field), fd.field.getName(), "唯一属性列值不能为空", rw);
                    }
                } catch (Exception e) {
                    rw.stop = true;
                    rw.status = STATIC_VALIDATE_FAIL;
                    addStaticFieldError(getFieldBizName(fd.field), fd.field.getName(), e.getMessage(), rw);
                }
            }
        }
    }

    private ImportResult createResult(List<RowWrapper> rows) {
        ImportResult ir = new ImportResult();
        ir.setTotal(rows.size());
        int skiped = 0;
        int success = 0;
        List<ImportRowResult> rowResults = new ArrayList<>();
        for (RowWrapper rw : rows) {
            if (rw.status == SAVE_SUCCESS) {
                success++;
            } else if (rw.status == SKIPED) {
                skiped++;
            }
            if (rw.rowResult != null) {
                rowResults.add(rw.rowResult);
            }
        }
        ir.setSkiped(skiped);
        ir.setFailed(ir.getTotal() - success - skiped);
        ir.setSucceed(success);
        ir.setRows(rowResults);
        return ir;
    }

    private void processAfterSave(DataDumpEntity anno, List<ImportEntityProcessor> importEntityProcessors, List<RowWrapper> rows) {
        if (importEntityProcessors.size() > 0) {
            for (RowWrapper rw : rows) {
                if (rw.stop) {
                    continue;
                }
                try {
                    for (ImportEntityProcessor p : importEntityProcessors) {
                        rw.transformed = p.processAfterSave(rw.origin, rw.transformed, anno);
                    }
                } catch (Exception e) {
                    addRowErrorMessage(rw, e.getMessage());
                    logger.error("第{}行数据后处理异常", rw.index, e);
                }

            }
        }
    }

    private void doSave(DataDumpEntity entityAnnotation, List<JPAQueryExportExecutor.FieldDescriptor> fieldDescriptors,
                        List<JPAQueryExportExecutor.FieldDescriptor> keyFields,
                        List<RowWrapper> rows, ImportDuplicateProcess duplicateProcess,
                        List<ImportEntityProcessor> importEntityProcessors
    ) throws IllegalAccessException {
        String moduleName = entityAnnotation.businessName();
        List<Object> entityList = new ArrayList<>();
        boolean stableEvalFlag = false;
        if (moduleName.equals("风险分区")) {
            stableEvalFlag = controlService.getStableCorFlag();
        }
//        if (moduleName.equals("危险源")) {
//            this.handleSkipRowsBySameCode(rows);
//        }
        for (RowWrapper rw : rows) {
            if (rw.stop) {
                continue;
            }
            try {
                List<Object> keyValues = extractFieldValues(keyFields, rw.transformed);
                List<Predicate> conditions = new ArrayList<>();
                for (int i = 0; i < keyFields.size(); i++) {
                    conditions.add(((SimpleExpression) keyFields.get(i).entityPath).eq(keyValues.get(i)));
                }
                EntityPathBase q = QueryDslUtils.findQEntityInstance(entityAnnotation.entity());
                tryAddLogicDeleteFlag(conditions, entityAnnotation, q);
                JPAQuery query = (JPAQuery) factory.select(q).from(q).where(conditions.toArray(new Predicate[0]));
                List list = query.fetch();
                if (list.isEmpty()) {
                    editSpcialData(rw, moduleName);
                    // 将目标属性值复制到
                    if (moduleName.equals("风险分区")) {
                        rw.transformed = copyRiskDistrictFieldValues(null, rw.transformed, stableEvalFlag);
                    }
                    processBeforePersist(rw, importEntityProcessors, entityAnnotation, false);
                    if (!rw.stop) {
                        // 处理未出异常
                        em.persist(rw.transformed);
                        rw.status = SAVE_SUCCESS;
                        entityList.add(rw.transformed);
                    }
                } else if (list.size() == 1) {
                    if (duplicateProcess == ImportDuplicateProcess.OVERRIDE) {
                        // 将目标属性值复制到
                        Map<String, Object> rawDaraMap = ReflectUtil.getKeyAndValue(list.get(0));
                        if (moduleName.equals("风险分区")) {
                            rw.transformed = copyRiskDistrictFieldValues(list.get(0), rw.transformed, stableEvalFlag);
                        } else {
                            copyFieldValues(list.get(0), rw.transformed, fieldDescriptors, moduleName);
                            rw.transformed = list.get(0);
                        }
                        processBeforePersist(rw, importEntityProcessors, entityAnnotation, true);
                        if (!rw.stop) {
                            // 处理未出异常
                            editSpcialData(rw, moduleName);
                            em.persist(list.get(0));
                            rw.status = SAVE_SUCCESS;
                            entityList.add(rw.transformed);
                        } else {
                            // 将数据复原
                            copyFieldValues(list.get(0), rawDaraMap, fieldDescriptors, moduleName);
                        }
                    } else {
                        rw.status = SKIPED;
                        rw.stop = true;
                    }
                } else {
                    logger.error("{}.{}#{}有多个值{}，不符合要求，请检查数据", entityAnnotation.entity().getName(), keyFields, keyValues, list);
                    rw.stop = true;
                    rw.status = SAVE_FAIL;
                    addRowErrorMessage(rw, "该行在数据库中查出多个值，不符合要求");
                }
            } catch (IllegalArgumentException e) {
                logger.error("{}数据导入异常", rw.transformed, e);
                rw.status = SAVE_FAIL;
                rw.stop = true;
                addRowErrorMessage(rw, e.getMessage());
            } catch (Exception e) {
                logger.error("保存实体{}异常", rw.transformed, e);
                rw.status = SAVE_FAIL;
                rw.stop = true;
                addRowErrorMessage(rw, "保存出错:" + e.getMessage());
            }
        }
        //批量同步数据
        if (CollectionUtils.isNotEmpty(entityList)) {
            batchSyncData(entityList, moduleName);
        }
    }

    private void handleSkipRowsBySameCode(List<RowWrapper> rows) {
        try {
            List<String> noSkipRows = Lists.newArrayList();
            List<String> nameRows = Lists.newArrayList();
            for (int i = rows.size() - 1; i >= 0; i--) {
                RowWrapper row = rows.get(i);
                MhMajorHazardDumpBean origin = (MhMajorHazardDumpBean) row.origin;
                ImportRowResult rowResult = row.rowResult;
                if (noSkipRows.contains(origin.getCode())) {
                    row.stop = true;
                    row.status = SKIPED;
                    addRowErrorMessage(row, "编号重复");
                    continue;
                }
                if (nameRows.contains(origin.getName())) {
                    row.stop = true;
                    row.status = SKIPED;
                    addRowErrorMessage(row, "危险源名称重复");
                    if (rowResult!=null){
                       rowResult.setFieldResults(Collections.EMPTY_LIST);
                    }
                    continue;
                }
                noSkipRows.add(origin.getCode());
                nameRows.add(origin.getName());
            }
        } catch (Exception e) {
            logger.error("处理编号重复异常!");
        }
    }

    // 检测非默认的逻辑删除
    public void tryAddLogicDeleteFlag(List<Predicate> conditions, DataDumpEntity entityAnnotation, EntityPathBase q) throws Exception {
        String field = entityAnnotation.batchDeleteField();
        if (!"deleteFlag".equals(field)) {
            com.querydsl.core.types.Path path = QueryDslUtils.findQPath(q, field);
            Object value = convertToType(entityAnnotation.deleteFlagValue(), path);
            SimpleExpression e = (SimpleExpression) path;
            conditions.add(e.ne(value).or(e.isNull()));
        }
    }

    private Object convertToType(String batchDeleteField, com.querydsl.core.types.Path path) throws ParseException {
        return HttpServletRequestQueryConditionBuilder.convertValueToType(batchDeleteField, path.getType());
    }

    private void editSpcialData(RowWrapper rw, String moduleName) {
        if (moduleName.equals("承包商")) {
            //设置同步id
            BpContractor entity = (BpContractor) rw.transformed;
            if (entity.getUniqueId() == null) {
                entity.setUniqueId(SnowFlakeUtil.getContractorId());
            }
            //状态为空 默认有效
            if (entity.getState() == null) {
                entity.setState(DataStateTypes.EFFECTIVE.getState());
            }

        } else if (moduleName.equals("承包商人员")) {
            BpContractorStaff entity = (BpContractorStaff) rw.transformed;
            if (entity.getUniqueId() == null) {
                entity.setUniqueId(SnowFlakeUtil.getContractorStaffId());
                entity.setLocateSync(false);
            }
            if (entity.getState() == null) {
                entity.setState(DataStateTypes.EFFECTIVE.getState());
            }
            //默认帽子图标
            if (entity.getCapId() == null) {
                entity.setCapId(1L);
            }
        } else if (moduleName.equals("岗位")) {
            //设置同步id
            BpJob entity = (BpJob) rw.transformed;
            if (entity.getUniqueId() == null) {
                entity.setUniqueId(SnowFlakeUtil.getJobId());
                entity.setLocateSync(false);
            }
        } else if (moduleName.equals("部门")) {
            BpDepart entity = (BpDepart) rw.transformed;
            if (entity.getUniqueId() == null) {
                entity.setUniqueId(SnowFlakeUtil.getDepartId());
                entity.setLocateSync(false);
            }
        } else if (moduleName.equals("风险点")) {
            RiskPoint riskPoint = (RiskPoint) rw.transformed;
            riskPoint.setStatus(RiskPointStatus.AUDIT_SUCCESS.getIndex());
            riskPoint.setState(0);
        }
    }


    private void batchSyncData(List<Object> entityList, String moduleName) {

        if (moduleName.equals("承包商")) {
            List<BpContractor> datas = new ArrayList<>();
            for (Object ob : entityList) {
                BpContractor ob1 = (BpContractor) ob;
                datas.add(ob1);
            }
            bpContractorService.batchSyncData(datas);
        } else if (moduleName.equals("承包商人员") && baseConfigService.checkIfSync()) {
            List<BpContractorStaff> datas = new ArrayList<>();
            for (Object ob : entityList) {
                BpContractorStaff ob1 = (BpContractorStaff) ob;
                datas.add(ob1);
            }
            bpContractorStaffService.batchSyncData(datas);
        } else if (moduleName.equals("岗位")) {
            for (Object ob : entityList) {
                BpJob ob1 = (BpJob) ob;
                ob1.setLocateSync(bpJobSyncService.syncjob(ob1));
                bpJobDao.save(ob1);
            }
        } else if (moduleName.equals("部门")) {
            for (Object ob : entityList) {
                BpDepart pDepart = null;
                BpDepart ob1 = (BpDepart) ob;
                if (ob1.getParentId() != null) {
                    Optional<BpDepart> obd = bpDepartDao.findById(ob1.getParentId());
                    if (obd.isPresent()) {
                        pDepart = obd.get();
                    }
                }
                ob1.setLocateSync(bpDepartSyncService.syncDepart(ob1, pDepart));
                bpDepartDao.save(ob1);
            }
        } else if (moduleName.equals("风险点")) {
            monitorPointDataWebSocketService.getRiskPointCount(Context.getCompanyCode().substring(0, 7), Context.getCurrentTenantId());
        } else if (moduleName.equals("风险区域")) {
            for (Object ob : entityList) {
                RiskDistrict district = (RiskDistrict) ob;
                riskEvaluationBusinessService.editDistrictLevel(district, district.getRiskLevel(), "区域划分");
            }
            monitorPointDataWebSocketService.getDistrictList(null, "ALL", Context.getCompanyCode(), Context.getCurrentTenantId());
        }
    }

    private void processBeforePersist(RowWrapper rw, List<ImportEntityProcessor> importEntityProcessors, DataDumpEntity entityAnnotation, boolean override) {
        if (importEntityProcessors.size() > 0) {
            for (ImportEntityProcessor p : importEntityProcessors) {
                try {
                    rw.transformed = p.processBeforePersist(rw.origin, rw.transformed, entityAnnotation, override);
                } catch (Exception e) {
                    rw.status = DYNAMIC_VALIDATE_FAIL;
                    rw.stop = true;
                    addRowErrorMessage(rw, e.getMessage());
                }
            }
        }
    }

    private void copyFieldValues(Object dbEntity, Object transformed, List<JPAQueryExportExecutor.FieldDescriptor> fieldDescriptors, String moduleName) throws IllegalAccessException, InvocationTargetException {
        Map<String, Object> rawDaraMap = null;
        if (transformed instanceof Map) {
            rawDaraMap = ((Map) transformed);
        }
        for (JPAQueryExportExecutor.FieldDescriptor fd : fieldDescriptors) {
            if (!fd.annotation.importIgnore()) {
                if (fd.needSetOtherEntity && moduleName.equals("风险点")) {
                    RiskPoint riskPoint = (RiskPoint) dbEntity;
                    riskPoint.setRiskDistrict(((RiskPoint) transformed).getRiskDistrict());
                } else if (MapUtils.isNotEmpty(rawDaraMap)) {
                    PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(dbEntity.getClass(), fd.entityFieldPd.getName());
                    pd.getWriteMethod().invoke(dbEntity, rawDaraMap.get(fd.entityFieldPd.getName()));
                } else {
                    PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(dbEntity.getClass(), fd.entityFieldPd.getName());
                    // 属性未忽略，或者忽略情况下值非空( ImportProcessor保存前赋值)
                    Object value = fd.entityFieldPd.getReadMethod().invoke(transformed);
                    pd.getWriteMethod().invoke(dbEntity, value);
                }
            }
        }
    }

    private Object copyRiskDistrictFieldValues(Object dbEntity, Object transformed, boolean stableEvalFlag) throws Exception {
        RiskDistrict oldDistrict = new RiskDistrict();
        if (dbEntity != null) {
            oldDistrict = (RiskDistrict) dbEntity;
        }
        RiskDistrict district = (RiskDistrict) transformed;
        if (oldDistrict.getId() != null) {
            org.springframework.util.Assert.isTrue(riskDistrictDao.countOfNameExcludeId(district.getName(), oldDistrict.getId()) == 0,
                    String.format("区域名称[%s]已存在", district.getName()));
        } else {
            org.springframework.util.Assert.isTrue(riskDistrictDao.countOfName(district.getName()) == 0, String.format("区域名称[%s]已存在", district.getName()));
        }
//        if (oldDistrict.getId() != null && stableEvalFlag && oldDistrict.getEvaluationState() != null && oldDistrict.getEvaluationState().equals(1)) {
//            if (!((oldDistrict.getStableRiskLevel() != null && district.getRiskLevel() != null && oldDistrict.getStableRiskLevel().equals(district.getRiskLevel()))
//                    || (null == district.getRiskLevel() && null == oldDistrict.getStableRiskLevel()))) {
//                throw new IllegalArgumentException("当前配置不支持修改区域等级,请关闭区域固有风险评价或者区域等级计算开关");
//            }
//        }
        RiskEvaluationBusiness evaluationBusiness = riskEvaluationBusinessDao.findByRiskDistrictId(oldDistrict.getId());
        Date lastDate = riskPointEvaluationBusinessDao.getLastEvalDateByDistrictId(oldDistrict.getId());
        if (lastDate == null && evaluationBusiness == null) {
            oldDistrict.setRealTimeRiskLevel(district.getRiskLevel().doubleValue());
            oldDistrict.setRiskLevel(district.getRiskLevel());
            oldDistrict.setInvestiageRiskLevel(district.getRiskLevel());
        }
        oldDistrict.setStableRiskLevel(district.getRiskLevel());
        oldDistrict.setName(district.getName());
        oldDistrict.setCode(district.getCode());
        oldDistrict.setType(district.getType());
        oldDistrict.setResponsibleDept(district.getResponsibleDept());
        oldDistrict.setResponsibleUser(district.getResponsibleUser());
        oldDistrict.setRemark(district.getRemark());
        return oldDistrict;
    }

    private List<Object> extractFieldValues(List<JPAQueryExportExecutor.FieldDescriptor> keyFields, Object transformed) throws IllegalAccessException, InvocationTargetException {
        List<Object> data = new ArrayList<>(keyFields.size());
        for (JPAQueryExportExecutor.FieldDescriptor fd : keyFields) {
//            System.err.println(fd.entityFieldPd);
//            System.err.println(transformed);
            data.add(fd.entityFieldPd.getReadMethod().invoke(transformed));
        }
        return data;
    }

    private void addRowErrorMessage(RowWrapper rw, String s) {
        if (rw.rowResult == null) {
            rw.rowResult = new ImportRowResult();
            rw.rowResult.setRowIndex(rw.index);
        }
        rw.rowResult.getMsgs().add(s);
    }

    private void processBeforeSave(DataDumpEntity anno, List<ImportEntityProcessor> importEntityProcessors, List<RowWrapper> rows) {
        if (importEntityProcessors.size() > 0) {
            for (RowWrapper rw : rows) {
                if (rw.stop) {
                    continue;
                }
                try {
                    for (ImportEntityProcessor p : importEntityProcessors) {
                        rw.transformed = p.processBeforeSave(rw.origin, rw.transformed, anno);
                    }
                } catch (Exception e) {
                    logger.error("JPAQueryImportExecutor processBeforeSave error ", e);
                    rw.stop = true;
                    rw.status = DYNAMIC_VALIDATE_FAIL;
                    addRowErrorMessage(rw, e.getMessage());
                }
            }
        }
    }

    private void createAndConvert(Class<F> entity, DataDumpEntity entityAnnotation, List<JPAQueryExportExecutor.FieldDescriptor> fieldDescriptors, List<RowWrapper> rows) throws Exception {
        EntityPathBase qEntity = QueryDslUtils.findQEntityInstance(entityAnnotation.entity());
        Class targetType = qEntity.getType();
        for (RowWrapper rw : rows) {
            if (rw.stop) {
                continue;
            }
            Object data = targetType.getDeclaredConstructor().newInstance();
            rw.transformed = data;
            for (JPAQueryExportExecutor.FieldDescriptor fd : fieldDescriptors) {
                if (fd.annotation.importIgnore()) {
                    // 忽略本字段
                    continue;
                }
                fd.field.setAccessible(true);
                Object originValue = fd.field.get(rw.origin);
                try {
                    // 先是用转换器
                    Object value = useConvertors(rw.origin, originValue, fd);
                    // 再查询是否是关联字段
                    value = tryGetRefentityPropertyValue(fd, value);
                    // 设置目标字段的值
                    setTargetObjectFieldValue(data, value, fd, rw);
                } catch (Exception e) {
                    rw.status = DYNAMIC_VALIDATE_FAIL;
                    addStaticFieldError(getFieldBizName(fd.field), fd.field.getName(), e.getMessage(), rw);
                    rw.stop = true;
                    logger.error("转换{}.{}异常", entity.getName(), fd.field.getName(), e);
                }
            }
        }
    }


    private Object tryGetRefentityPropertyValue(JPAQueryExportExecutor.FieldDescriptor fd, Object value) throws Exception {
        if (value == null || fd.refEntity == null) {
            return value;
        }
        List<Predicate> conditions = new ArrayList<>();
        conditions.add(((SimpleExpression) fd.refEntityPath).eq(value));
        // FIXME 根据关联实体类型，增加逻辑删除条件
        tryAddRefEntityLogicDeleteFlagCondition(conditions, fd.refEntity);
        JPAQuery query = null;
        if (fd.needSetOtherEntity) {
            query = (JPAQuery) factory.select(fd.refEntity).from(fd.refEntity).where(conditions.toArray(new Predicate[0]));
        } else {
            query = (JPAQuery) factory.select(fd.refEntityIdPath).from(fd.refEntity).where(conditions.toArray(new Predicate[0]));
        }
        List list = query.fetch();
        if (list.isEmpty()) {
            if (fd.annotation.createRefEntityWhenNotExists()) {
                if (!fd.needSetOtherEntity) {
                    Object target = createRefEntity(value, fd);
                    em.persist(target);
                    return getObjectValue(target, fd.annotation.referenceEntityIdField());
                }
            } else {
                Assert.notEmpty(list,
                        fd.annotation.refEntityNotExistsMessage().length() > 0 ? fd.annotation.refEntityNotExistsMessage() + " " : "【" + value + "】不存在，请检查确认! ");
            }
        }
        if (fd.needSetOtherEntity) {
            if (list.size() == 1) {
                return list.get(0);
            } else {
                throw new IllegalArgumentException("系统存在多个相同对象，请确保唯一性");
            }
        } else {
            if (list.size() == 1) {
                Object v = list.get(0);
                if (fd.needSetOtherEntity) {
                    return v;
                } else {
                    return (v instanceof Tuple) ? ((Tuple) v).get(fd.refEntityIdPath) : v;
                }
            } else {
                MultiRefEntityChooseStrategy strategy = fd.annotation.multiRefEntityChooseStragey();
                if (strategy == MultiRefEntityChooseStrategy.ABORT) {
                    throw new IllegalArgumentException("系统存在多个相同对象，请确保唯一性");
                } else if (strategy == MultiRefEntityChooseStrategy.FIRST) {
                    Object v = list.get(0);
                    return (v instanceof Tuple) ? ((Tuple) v).get(fd.refEntityIdPath) : v;
                } else {
                    Object v = list.get(list.size() - 1);
                    return (v instanceof Tuple) ? ((Tuple) v).get(fd.refEntityIdPath) : v;
                }
            }
        }
    }

    /**
     * 查找refEntity是否注册了导入信息，如果注册，尝试应用refEntity的逻辑删除条件
     *
     * @param conditions
     * @param referenceEntity
     * @throws Exception
     */
    private void tryAddRefEntityLogicDeleteFlagCondition(List<Predicate> conditions, EntityPathBase referenceEntity) throws Exception {
        // 该referenceEntity对应的class, 不是getType(),注意
        DataDumpEntity refAnnotation = dataDumpDefRegistry.findAnnotationByQEntityType(referenceEntity.getClass());
        if (refAnnotation != null) {
            logger.debug("Q class {} register annotation {}", referenceEntity.getClass().getName(), refAnnotation.getClass().getName());
            tryAddLogicDeleteFlag(conditions, refAnnotation, referenceEntity);
        }
    }

    private Object getObjectValue(Object target, String fieldName) throws InvocationTargetException, IllegalAccessException {
        PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(target.getClass(), fieldName);
        return pd.getReadMethod().invoke(target);
    }

    private Object createRefEntity(Object value, JPAQueryExportExecutor.FieldDescriptor fd) throws Exception {
        EntityPathBase qEntity = QueryDslUtils.findQEntityInstance(fd.annotation.referenceEntity());
        Class targetType = qEntity.getType();
        Object target = targetType.getDeclaredConstructor().newInstance();
        PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(targetType, fd.annotation.referenceEntityField());
        pd.getWriteMethod().invoke(target, value);
        return target;
    }

    private Object useConvertors(Object bean, Object value, JPAQueryExportExecutor.FieldDescriptor fd) {
        Class<? extends FieldValueConvert>[] convertors = fd.annotation.importConvertors();
        if (convertors.length == 0) {
            return value;
        }
        for (Class<? extends FieldValueConvert> c : convertors) {
            value = applicationContext.getBean(c).convert(bean, value, fd.annotation);
        }
        return value;
    }

    private void setTargetObjectFieldValue(Object data, Object value, JPAQueryExportExecutor.FieldDescriptor fd, RowWrapper rw) throws InvocationTargetException, IllegalAccessException {
        if (fd.needSetOtherEntity && data.getClass().equals(RiskPoint.class) && fd.refEntity.getMetadata().getElement().equals("riskDistrict")) {
            ((RiskPoint) rw.transformed).setRiskDistrict((RiskDistrict) value);
        } else {
            String fieldName = fd.entityPath.getMetadata().getName();
            PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(data.getClass(), fieldName);
            Assert.notNull(pd.getWriteMethod(), String.format("%s字段%s没有写入方法 ", data.getClass().getName(), fieldName));
            pd.getWriteMethod().invoke(data, value);
        }
    }

    private void customValidator(Class<F> entity, List<RowWrapper> rows) throws Exception {
        for (RowWrapper rw : rows) {
            Map<String, Object> map = new HashMap();
            Object origin = rw.origin;
            Field[] fields = origin.getClass().getDeclaredFields();
            for (Field field : fields) {
                try {
                    field.setAccessible(true);
                    // 得到此属性的值 设置键值
                    map.put(field.getName(), field.get(origin));
                    CustomValidator annotation = field.getAnnotation(CustomValidator.class);
                    if (annotation != null) {
                        notNullCheck(annotation, field, map, rw, origin);
                        valueCheckJson(annotation, field, map, rw, origin);
                    }
                } catch (Exception e) {
                    rw.status = DYNAMIC_VALIDATE_FAIL;
                    addStaticFieldError(getFieldBizName(field), field.getName(), e.getMessage(), rw);
                    rw.stop = true;
                }
            }
        }
    }

    private void notNullCheck(CustomValidator annotation, Field field, Map<String, Object> map, RowWrapper rw, Object newInstance) throws IllegalAccessException {
        // 校验不为空
        String json = annotation.notNull();
        // 当前值
        Object value = field.get(newInstance);
        if (StrUtil.isBlank(json) && Objects.isNull(value)) {
            addStaticFieldError(getFieldBizName(field), field.getName(), "值不能为空", rw);
            return;
        }
        if (StrUtil.isBlank(json)) {
            return;
        }
        CustomNotNull customNotNull = JSONUtil.toBean(json, CustomNotNull.class);
        // 关联字段的值
        Object relatedFieldValue = map.get(customNotNull.getRelatedField());

        if (StrUtil.isNotBlank(customNotNull.getRelatedFieldNotValue()) &&
                !customNotNull.getRelatedFieldNotValue().equals(relatedFieldValue) && Objects.isNull(value)) {
            rw.status = DYNAMIC_VALIDATE_FAIL;
            addStaticFieldError(getFieldBizName(field), field.getName(), "值不能为空", rw);
        }
        if (StrUtil.isNotBlank(customNotNull.getRelatedFieldValue()) &&
                customNotNull.getRelatedFieldValue().equals(relatedFieldValue) && Objects.isNull(value)) {
            rw.status = DYNAMIC_VALIDATE_FAIL;
            addStaticFieldError(getFieldBizName(field), field.getName(), "值不能为空", rw);
        }

    }

    private void valueCheckJson(CustomValidator annotation, Field field, Map<String, Object> map, RowWrapper rw, Object newInstance) throws IllegalAccessException {
        // 校验值
        String valueCheckJson = annotation.valueCheck();
        if (StrUtil.isBlank(valueCheckJson)) {
            return;
        }
        CustomValueCheck customValueCheck = JSONUtil.toBean(valueCheckJson, CustomValueCheck.class);
        // 关联字段的值
        Object relatedFieldValue = map.get(customValueCheck.getRelatedField());
        // 当前值
        String value = Convert.toStr(field.get(newInstance));
        if (StrUtil.isEmpty(value)) {
            return;
        }
        // 校验当前值是否匹配 正则表达式
        boolean matches = Pattern.matches(customValueCheck.getRegexp(), value);

        if (StrUtil.isNotBlank(customValueCheck.getRelatedFieldNotValue()) &&
                !customValueCheck.getRelatedFieldNotValue().equals(relatedFieldValue) && !matches) {
            rw.status = DYNAMIC_VALIDATE_FAIL;
            addStaticFieldError(getFieldBizName(field), field.getName(), customValueCheck.getMessage(), rw);
        }
        if (StrUtil.isNotBlank(customValueCheck.getRelatedField()) &&
                customValueCheck.getRelatedField().equals(relatedFieldValue) && !matches) {
            rw.status = DYNAMIC_VALIDATE_FAIL;
            addStaticFieldError(getFieldBizName(field), field.getName(), customValueCheck.getMessage(), rw);
        }
    }

    private void staticValidate(Class<F> entity, List<RowWrapper> rows) throws
            NoSuchFieldException, IllegalAccessException {
        Validator validator = validatorFactory.getValidator();
        Class[] groups = new Class[0];
        for (RowWrapper rw : rows) {
            Set validateResult = validator.validate(rw.origin, groups);
            if (validateResult.isEmpty()) {
                rw.status = STATIC_VALIDATE_PASS;
            } else {
                Iterator iterator = validateResult.iterator();
                while (iterator.hasNext()) {
                    ConstraintViolation violation = (ConstraintViolation) iterator.next();
                    extractErrors(violation, rw);
                }
                rw.stop = true;
            }
        }
    }

    private void extractErrors(ConstraintViolation violation, RowWrapper rw) throws
            IllegalAccessException, NoSuchFieldException {
        Path path = violation.getPropertyPath();
        Iterator<Path.Node> it = path.iterator();
        Object target = rw.origin;
        while (it.hasNext()) {
            Path.Node node = it.next();
            String fieldName = node.getName();
            Field f = getField(target, fieldName);
            f.setAccessible(true);
            target = f.get(target);
            if (!it.hasNext()) {
                // 叶子节点
                String fieldBizName = getFieldBizName(f);
                addStaticFieldError(fieldBizName, fieldName, violation.getMessage(), rw);
            }

        }
    }

    private void addStaticFieldError(String fieldBizName, String fieldName, String message, RowWrapper<F, T> rw) {
        if (rw.rowResult == null) {
            rw.rowResult = new ImportRowResult();
            rw.rowResult.setRowIndex(rw.index);
            createNewFieldResult(fieldBizName, fieldName, message, (RowWrapper<F, T>) rw);
        } else {
            ImportFieldResult first = rw.rowResult.getFieldResults().stream().filter(v -> v.getName().equals(fieldBizName)).findFirst().orElse(null);
            if (first == null) {
                createNewFieldResult(fieldBizName, fieldName, message, (RowWrapper<F, T>) rw);
            } else {
                first.getErrors().add(message);
            }
        }
    }

    private void createNewFieldResult(String fieldBizName, String fieldName, String message, RowWrapper<F, T> rw) {
        ImportFieldResult r = new ImportFieldResult();
        r.setName(fieldBizName);
        r.setField(fieldName);
        List<String> errors = new ArrayList<>(5);
        errors.add(message);
        r.setErrors(errors);
        rw.rowResult.getFieldResults().add(r);
    }

    private String getFieldBizName(Field f) {
        Excel a = f.getAnnotation(Excel.class);
        if (a != null) {
            return a.name();
        }
        return f.getName();
    }

    private Field getField(Object target, String fieldName) throws NoSuchFieldException {
        return target.getClass().getDeclaredField(fieldName);
    }


    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }


    static class RowWrapper<F, T> {
        F origin;
        T transformed;
        int index;
        boolean stop;
        int status;

        ImportRowResult rowResult;

    }

    static final int INIT = 0;
    static final int STATIC_VALIDATE_PASS = 1;
    static final int STATIC_VALIDATE_FAIL = 2;
    static final int DYNAMIC_VALIDATE_PASS = 3;
    static final int DYNAMIC_VALIDATE_FAIL = 4;
    static final int SAVE_SUCCESS = 7;
    static final int SAVE_FAIL = 8;
    static final int SKIPED = 9;
}
